package com.hdd.utils.wx;

import com.baidu.aip.util.Base64Util;
import org.apache.commons.lang3.StringUtils;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

/**
 * @author ;xuhu
 * @Description:
 * @Date: 2020-11-27 15:45
 **/

public class AESUtil {


    /**
     * 生成key，作为加密和解密密钥且只有密钥相同解密加密才会成功
     *
     * @return
     */
    public static String createKey() {

        try {
            // 生成key
            KeyGenerator keyGenerator;
            //构造密钥生成器，指定为AES算法,不区分大小写
            keyGenerator = KeyGenerator.getInstance("AES");
            //生成一个128位的随机源,根据传入的字节数组
            keyGenerator.init(128);
            //产生原始对称密钥
            SecretKey secretKey = keyGenerator.generateKey();
            //获得原始对称密钥的字节数组
            byte[] keyBytes = secretKey.getEncoded();
            return parseByte2HexStr(keyBytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return "";
        }

    }

    /**
     * 生成偏移量，作为加密和解密密钥且只有密钥相同解密加密才会成功
     *
     * @return
     */
    public static String createIv() {
        String key = createKey();
        if (StringUtils.isBlank(key)) {
            return "";
        }
        return Base64Util.encode(key.getBytes());

    }


    /**
     * AES加密
     *
     * @param encryptStr 需要加密的数据
     * @param key        加密使用的key
     * @param ivStr      偏移量
     * @return 加密后的数据
     */
    public static String encryptAes(String encryptStr, String key, String ivStr) {
        byte[] encryptedBytes = null;
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec secretKeySpec = new SecretKeySpec(parseHexStr2Byte(key), "AES");
            IvParameterSpec iv = new IvParameterSpec(parseHexStr2Byte(new String(Base64Util.decode(ivStr))));
            cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
            encryptedBytes = cipher.doFinal(encryptStr.getBytes());
        } catch (NoSuchAlgorithmException | InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException e) {
            e.printStackTrace();
        }
        if (encryptedBytes == null) {
            return "加密失败";
        }
        return parseByte2HexStr(encryptedBytes);
    }

    /**
     * AES解密
     *
     * @param encryptStr 需要解密的数据
     * @param key        解密使用的key
     * @param ivStr      偏移量
     * @return 解密后的数据
     */
    public static String decryptAes(String encryptStr, String key, String ivStr) {
        byte[] decryptedBytes = null;
        try {
            Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
            SecretKeySpec secretKeySpec = new SecretKeySpec(parseHexStr2Byte(key), "AES");
            IvParameterSpec iv = new IvParameterSpec(parseHexStr2Byte(new String(Base64Util.decode(ivStr))));
            cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
            decryptedBytes = cipher.doFinal(parseHexStr2Byte(encryptStr));
        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | InvalidAlgorithmParameterException e) {
            e.printStackTrace();
        }
        if (decryptedBytes == null) {
            return "解密失败";
        }
        return new String(decryptedBytes);
    }


    /**
     * 将二进制转换成16进制
     *
     * @param buf
     * @return
     */
    private static String parseByte2HexStr(byte[] buf) {
        StringBuilder sb = new StringBuilder();
        for (byte b : buf) {
            String hex = Integer.toHexString(b & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**
     * 将16进制转换为二进制
     *
     * @param hexStr
     * @return
     */
    private static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr == null || hexStr.length() < 1) {
            return null;
        }
        byte[] result = new byte[hexStr.length() / 2];
        for (int i = 0; i < hexStr.length() / 2; i++) {
            int high = Integer.parseInt(hexStr.substring(i * 2, i * 2 + 1), 16);
            int low = Integer.parseInt(hexStr.substring(i * 2 + 1, i * 2 + 2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    public static void main(String[] args) {
        String key = createKey();
        System.out.println(key);
        String iv = createIv();
        System.out.println(iv);
//        String key = "6EF72DD432A512289FD6918C49032FAF";
        long l = System.currentTimeMillis();
        String encryptDES = encryptAes("eyJhbGciOiJIUzI1NiJ9.eyJMT0dJTl9VU0VSX0tFWSI6ImU3ZjczYTBhLWI4NGQtNGE4Yi05ZDY3LTQ3ODEzZjg2MWUwOCJ9.tJk5tk4IdrzNzFbjGXgR2VlO6R74F67LkAIAHlleRdk", key, iv);
        System.out.println(System.currentTimeMillis() - l);
        System.out.println(encryptDES);
        String s = decryptAes(encryptDES, key, iv);
        System.out.println(s);
    }


}